//========================================================================
//Copyright 2007-2010 David Yu dyuproject@gmail.com
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at 
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================

package com.dyuproject.kvstore.gae;

import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import com.dyuproject.kvstore.Serializer;
import com.dyuproject.kvstore.Store;
import com.dyuproject.kvstore.StoreManager;

/**
 * Manages the gae datastores.
 *
 * @author David Yu
 * @created Jan 29, 2010
 */
public final class GAEStoreManager implements StoreManager
{
    
    static <T> GAEStore<T> newStore(String name, Serializer<T> serializer, Properties props)
    {
        String maxRetriesParam = props.getProperty(name + ".gaestore_max_retries");
        if(maxRetriesParam == null)
            maxRetriesParam = props.getProperty("gaestore.max_retries");
        
        int maxRetries = maxRetriesParam == null ? GAEStore.DEFAULT_MAX_RETRIES : 
            Integer.parseInt(maxRetriesParam);
        return new GAEStore<T>(serializer, null, name, maxRetries);
    }
    
    private Properties props;
    private final ConcurrentHashMap<String, Lazy<?>> stores = 
        new ConcurrentHashMap<String, Lazy<?>>();

    public void close()
    {
        // gae closes their stores with their servlet filters.
    }

    @SuppressWarnings("unchecked")
    public <T> Store<T> getStore(String name, Serializer<T> serializer)
    {
        Lazy<T> lazy = (Lazy<T>)stores.get(name);
        if(lazy==null)
        {
            lazy = new Lazy<T>(name, serializer);
            Lazy<T> last = (Lazy<T>)stores.putIfAbsent(name, lazy);
            if(last!=null)
                lazy = last;
        }
        if(lazy.serializer != serializer)
        {
            throw new IllegalArgumentException("The store '" + name + 
                    "' already exists with a different serializer.");
        }
        
        return lazy.getStore();
    }

    public synchronized void init(Properties props)
    {
        if(props == null)
            this.props = props;
    }
    
    private final class Lazy<T>
    {
        final String name;
        final Serializer<T> serializer;
        private GAEStore<T> store;
        
        public Lazy(String name, Serializer<T> serializer)
        {
            this.name = name;
            this.serializer = serializer;
        }

        public GAEStore<T> getStore()
        {
            GAEStore<T> store = this.store;
            if(store==null)
            {
                synchronized(this)
                {
                    store = this.store;
                    if(store==null)
                    {
                        store = this.store = newStore(name, serializer, props);
                    }
                }
            }

            return store;
        }
    }

}
